#include "HttpIncomingRequest.h"

std::shared_ptr<CHttpIncomingRequest> CHttpIncomingRequest::Parse(const CString &InRequestString)
{
    //find first CRLF , this is the end of request line
    int64_t FirstCRLFIndex = InRequestString.Find(U"\r\n");
    
    //if not found, return nullptr
    if(FirstCRLFIndex<0)
    {
        return nullptr;
    }

    auto Request = std::make_shared<CHttpIncomingRequest>();

    //parse request line
    {
        //get request line string
        CString RequestLineString = InRequestString.SubString(0,FirstCRLFIndex);

        //find first space, this is the end of method
        int64_t FirstSpaceIndex = RequestLineString.Find(U" ");

        //if not found, return nullptr
        if(FirstSpaceIndex<0)
        {
            return nullptr;
        }

        //get method string
        CString MethodString = RequestLineString.SubString(0,FirstSpaceIndex);

        //parse method
        Request->Method  = WH::StringToRequestMethod(MethodString);
      
        //find second space, this is the end of url
        auto SecondSpaceIndex = RequestLineString.Find(U' ',FirstSpaceIndex+1);

        //if not found, return nullptr
        if(SecondSpaceIndex<0)
        {
            return nullptr;
        }

        //get request path string
        CString PathString = RequestLineString.SubString(FirstSpaceIndex+1,SecondSpaceIndex-FirstSpaceIndex-1);

        //parse path
        {
            //check if path contains ?
            auto QuestionMarkIndex = PathString.Find(U'?');
            if(QuestionMarkIndex>0)
            {
                Request->ResoucePath = PathString.SubString(0,QuestionMarkIndex);

                auto QuestionString = PathString.SubString(QuestionMarkIndex+1,PathString.GetLength()-QuestionMarkIndex-1);

                //split by &
                auto Parameters = QuestionString.Split(U'&');

                for(auto &Parameter:Parameters)
                {
                    //split by =
                    auto KeyValue = Parameter.Split(U'=');
                    if(KeyValue.Num()==2)
                    {
                        Request->UrlParameters.Add(KeyValue[0],KeyValue[1]);
                    }
                    else
                    {
                        //invalid parameter
                        return nullptr;
                    }
                }
            }
            else
            {
                //no parameters
                Request->ResoucePath = PathString;
            }




        }


        //get http version string
        Request->Version = RequestLineString.SubString(SecondSpaceIndex+1,RequestLineString.GetLength()-SecondSpaceIndex-1);



        //create request
        // auto Request = std::make_shared<CHttpRequest>();
        // Request->Method = Method;
        // Request->Url = Url.GetValue

    }

    //find first CRLFCRLF, this is the end of request head
    int64_t CRLFCRLFIndex = InRequestString.Find(U"\r\n\r\n",FirstCRLFIndex); 

    //if not found, return nullptr
    if(CRLFCRLFIndex<0)
    {
        //cant find empty line
        return nullptr;
    }


    //parse head
    {
        auto HeadString = InRequestString.SubString(FirstCRLFIndex+2,CRLFCRLFIndex-FirstCRLFIndex-2);

        //split by CRLF
        auto HeadLines = HeadString.Split(U"\r\n");

        for(auto &HeadLine:HeadLines)
        {
            //split by :
            auto Colon = HeadLine.Find(U':');
            if(Colon<0)
            {
                //invalid head line
                return nullptr;
            }

            auto HeadName = HeadLine.SubString(0,Colon);
            auto HeadValue = HeadLine.SubString(Colon+1,HeadLine.GetLength()-Colon-1);
            Request->Headers.Add(HeadName,HeadValue);
        }
    }

    //try find body
    if(CRLFCRLFIndex+4<InRequestString.GetLength())
    {
        Request->Body = InRequestString.SubString(CRLFCRLFIndex+4,InRequestString.GetLength()-CRLFCRLFIndex-4);
    }

    return Request;
}
